//Copyright (C) 2012 Chirila Alexandru
//This file is part of Robo-GoldMiner
//
//Robo-GoldMiner is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//Robo-GoldMiner is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with Robo-GoldMiner.  If not, see <http://www.gnu.org/licenses/>.

package gold;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.LinkedList;

/**
 * Every command should be executed through this class, in order to 
 * create the undo/redo stacks. Functions should have the StackCommands
 * send to them to execute.
 * @author Alexandru Chirila
 */
public class StackCommands implements Serializable {

	private static final long serialVersionUID = 8674854285159462734L;
	private LinkedList<UndoCommand> undoStack = new LinkedList<UndoCommand>();
	private LinkedList<UndoCommand> redoStack = new LinkedList<UndoCommand>();

	public StackCommands() {

	}

	public void clearAll() {
		undoStack.clear();
		redoStack.clear();
	}

	/**
	 * Executes the command, and save a copy of it if the command is undoable
	 * @param cmd
	 * @throws EndGame
	 * @throws ParseException
	 */
	public void execute(Command cmd) throws EndGame, ParseException {

		if (cmd.execute()) {
			if (UndoCommand.class.isAssignableFrom(cmd.getClass())) {
				undoStack.push(((UndoCommand) cmd).copy());
			}
		}

	}

	public boolean stepUndo() throws ParseException {

		UndoCommand cmd;

		if (!undoStack.isEmpty()) {

			cmd = (UndoCommand) undoStack.pop();
			cmd.undo();
			redoStack.push(cmd);
			return true;

		} else {
			return false;
		}
	}

	public boolean stepRedo() throws EndGame, ParseException {

		UndoCommand cmd;

		if (!redoStack.isEmpty()) {

			cmd = (UndoCommand) redoStack.pop();
			execute(cmd);
			return true;

		} else {
			return false;
		}
	}

	public void runStack() throws EndGame, ParseException{
		for (int i = undoStack.size()-1; i >= 0; i--) {
			undoStack.get(i).execute();
		}
	}
	
	private void writeObject(ObjectOutputStream stream) throws IOException {
		stream.defaultWriteObject();
	}

	private void readObject(ObjectInputStream stream) throws IOException,
			ClassNotFoundException {
		stream.defaultReadObject();
	}

	public static StackCommands loadStack(String file)
			throws FileNotFoundException, IOException, ClassNotFoundException {
		ObjectInputStream stream = new ObjectInputStream(new FileInputStream(
				file));

		StackCommands newStack = (StackCommands) stream.readObject();

		return newStack;
	}

	public static void saveStack(StackCommands stack, String file)
			throws FileNotFoundException, IOException {

		ObjectOutputStream stream = new ObjectOutputStream(
				new FileOutputStream(file));

		stream.writeObject(stack);
	}
}
